function TestCtrl($scope) {
  $scope.tests = {
    'parser_1': {
      expected: 'p&q',
      actual: displayExpression(
        parser.parse('p&q', 'expression'), BASE_STUDENT_LANGUAGE.operators)
    },
    'parser_2': {
      expected: '(p+q)=r',
      actual: displayExpression(
        parser.parse('p+q=r', 'expression'), BASE_STUDENT_LANGUAGE.operators)
    },
    'parser_3': {
      expected: 'p<(@x.(2+2))',
      actual: displayExpression(
        parser.parse('p<@x.2+2', 'expression'), 
        BASE_STUDENT_LANGUAGE.operators)
    },
    'parser_4': {
      expected: '((x=2)&($y.(y=6)))=>valid',
      actual: displayExpression(
        parser.parse('(x=2)&$y.y=6=>valid', 'expression'), 
        BASE_STUDENT_LANGUAGE.operators)
    },
    'parser_5': {
      expected: 'p|(@m?S.A(m,S))',
      actual: displayExpression(
        parser.parse('p|@m?S.A(m,S)', 'expression'), 
        BASE_CONTROL_LANGUAGE.operators)
    },
    'parser_6': {
      expected: 'min{a<b | p|(q&r)}',
      actual: displayExpression(
        parser.parse('min{a<b|(p|q&r)}', 'expression'), 
        BASE_CONTROL_LANGUAGE.operators)
    },
    'pre_parse_line_1': {
      expected: JSON.stringify(['from', 'p', 'and', 'q', 'we', 'have', 'p&q']),
      actual: JSON.stringify(preParseLine('from p and q we have p&q', BASE_STUDENT_LANGUAGE.operators, false).output)
    },
    'pre_parse_line_2': {
      expected: JSON.stringify({
        output: ['from', 'p|(q&r)', 's', 'we', 'see', '@x.r'], 
        indentation: 2
      }),
      actual: JSON.stringify(
        preParseLine(
          '    from p | (q& r ) s we see @ x. r', 
          BASE_STUDENT_LANGUAGE.operators, false))
    },
    'pre_parse_line_3': {
      error: 'This line is blank.',
      actual: function() {
        preParseLine('      ', BASE_STUDENT_LANGUAGE.operators, false);
      }
    },
    'pre_parse_line_4': {
      error: 'An indentation is indicated by a double space at the start of the line, but this line starts with an odd number of spaces.',
      actual: function() {
        preParseLine(' from p and q', BASE_STUDENT_LANGUAGE.operators, false)
      }
    },
    'pre_parse_line_5': {
      error: 'The symbol { was not recognised.',
      actual: function() {
        preParseLine('from p and p{q we see q', BASE_STUDENT_LANGUAGE.operators, false);
      }
    },
    'pre_parse_line_6': {
      expected: JSON.stringify({
        output: ['from', 'p[x->a]', 'at', '{{a|variable}}', 'have', 'q']
      }),
      actual: JSON.stringify(
        preParseLine(
          'from p [ x -> a ] at {{ a | variable }} have q', 
          BASE_STUDENT_LANGUAGE.operators, true))
    },
    'parse_line_1': {
      expected: JSON.stringify({
        results:[[{
          format: 'phrase',
          content: 'from'
        },{
          format: 'expression',
          content: {
            kind: 'variable', 
            operator: 'p',
            arguments:[],
            dummies:[]
          }
        },{
          format: 'phrase',
          content: 'and'
        },{
          format: 'expression',
          content: {
            kind:'variable',
            operator: 'q',
            arguments: [],
            dummies:[]
          }
        },{
          format: 'phrase',
          content: 'have'
        },{
          format: 'expression',
          content: {
            kind: 'binary_connective',
            operator: 'and',
            arguments: [{
              kind: 'variable',
              operator: 'p',
              arguments: [],
              dummies: []
            },{
              kind: 'variable',
              operator: 'q',
              arguments: [],
              dummies: []
            }],
            dummies:[]
          }
        }]],
        indentation :0
      }),
      actual: JSON.stringify(parseLine('from p and q we have p&q', BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY, false))
    },
    'parse_line_2': {
      error: 'The phrase starting \'we\' could not be identified; please make sure you are only using phrases from the given list of vocabulary.',
      actual: function() {
        parseLine('from p we havw p&q', BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY, false);
      }
    },
    'parse_line_3': {
      expected: 2,
      actual: parseLine('from p[x->a] we know hence a contradiction {{ a | element }}', BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY, true).results.length
    },
    'parse_line_4': {
      error: 'We could not identify \'B\'; please make sure you are using vocabulary from the given list, and don\'t have two consecutive expressions.',
      actual: function () {
        parseLine('from A=>B B have B', BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY, false);
      }
    },
    'assign_types_1': {
      expected: JSON.stringify({
        operator:"p",
        kind:"variable",
        arguments:[],
        dummies:[],
        type:"boolean"}),
      actual: JSON.stringify(
        assignTypesToExpression(
          parser.parse('p', 'expression'), ['boolean'], BASE_STUDENT_LANGUAGE, 
          ['variable']
        )[0].typedExpression
      )
    },
    'assign_types_2': {
      expected: JSON.stringify({
        operator:"and",
        kind:"binary_connective",
        arguments:[{
          operator:"p",
          kind:"variable",
          arguments:[],
          dummies:[],
          type:"boolean"
        },{
          operator:"equals",
          kind:"binary_relation",
          arguments:[{
            operator:"x",
            kind:"variable",
            arguments:[],
            dummies:[],
            type:"element"
          },{
            operator:"y",
            kind:"variable",
            arguments:[],
            dummies:[],
            type:"element"
          }],
          dummies:[],
          type:"boolean"
        }],
        dummies:[],
        type:"boolean"
      }),
      actual: JSON.stringify(
        assignTypesToExpression(
          parser.parse('p&x=y', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, ['variable']
        )[0].typedExpression
      )
    },
    'assign_types_3': {
      error: 'addition yields a element but you are trying to use it to give a boolean.',
      actual: function() {assignTypesToExpression(
        parser.parse('p<=>2+x', 'expression'), ['boolean'], 
        BASE_STUDENT_LANGUAGE, 
        ['variable']
      )}
    },
    'assign_types_4': {
      error: 'The name \'a\' is already in use and so cannot be quantified over in $a.f(2).',
      actual: function() {
        assignTypesToExpression(
          parser.parse('a&$a.f(2)', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, 
          ['variable', 'prefix_function', 'constant']
        )
      }
    },
    'assign_types_5': {
      error: 'f is supposed to be a prefix_function.',
      actual: function() {
        assignTypesToExpression(
          parser.parse('f(f)', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, 
          ['variable', 'prefix_function', 'constant']
        )
      }
    },
    'assign_types_6': {
      error: 'The operator bounded_for_all could not be identified.',
      actual: function() {
        assignTypesToExpression(
          parser.parse('@m<n.A(n)', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, 
          ['variable', 'prefix_function', 'constant']
        )
      }
    },
    'assign_types_7': {
      error: 'x yields a boolean but you are trying to use it to give a element.',
      actual: function() {
        assignTypesToExpression(
          parser.parse('x&f(x)', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, 
          ['variable', 'prefix_function', 'constant']
        )
      }
    },
    'assign_types_8': {
      expected: '$x.(x=x)',
      actual: displayExpression(
        assignTypesToExpression(
          parser.parse('$x.x=x', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, []
        )[0].typedExpression, BASE_STUDENT_LANGUAGE.operators
      )
    },
    'assign_types_9': {
      error: 'The operator x could not be identified.',
      actual: function() {
        assignTypesToExpression(
          parser.parse('$x.A(x)<=>x=2', 'expression'), ['boolean'], 
          BASE_STUDENT_LANGUAGE, ['prefix_function', 'constant']
        )
      }
    },
    'assign_types_10': {
      error: '2 yields a integer but you are trying to use it to give a string.',
      actual: function() {
        assignTypesToExpression(
          parser.parse('\'a\'=2', 'expression'), ['boolean'], 
          BASE_CONTROL_LANGUAGE, ['prefix_function', 'constant']
        )
      }
    },
    'check_expressions_equal_1': {
      expected: true,
      actual: checkExpressionsAreEqual(parser.parse('p&r|@x.s', 'expression'), parser.parse('(p&r)|(@x.s)', 'expression'))
    },
    'check_expressions_equal_2': {
      expected: false,
      actual: checkExpressionsAreEqual(parser.parse('p&r|@x.s', 'expression'), parser.parse('(p&r)|(@y.s)', 'expression'))
    },
    'check_expression_in_set': {
      expected: false,
      actual: checkExpressionIsInSet(
        parser.parse('p&q', 'expression'), 
        [
          parser.parse('A(x)', 'expression'), 
          parser.parse('q&p', 'expression')
        ])
    },
    'check_expression_sets_equal': {
      expected: true,
      actual: checkSetsOfExpressionsAreEqual([
          parser.parse('A(x)|x=2', 'expression'),
          parser.parse('p', 'expression')
        ], [
          parser.parse('p', 'expression'),
          parser.parse('A(x)|(x=2)', 'expression'),
          parser.parse('p', 'expression')
        ])
    },
    'get_operators_1': {
      expected: 'x 2 addition f y equals p and',
      actual: getOperatorsFromExpression(parser.parse('f(x+2)=y+x&p', 'expression')).join(' ')
    },
    'get_operators_2': {
      expected: 'x y',
      actual: getOperatorsFromExpression(parser.parse('x+2=y+x', 'expression'), ['variable']).join(' ')
    },
    'greater_than_lex_1': {
      expected: true,
      actual: greaterThanInLex([1,2,4,4], [1,2,3,5])
    },
    'greater_than_lex_2': {
      expected: false,
      actual: greaterThanInLex([1,2], [1,2])
    }
  };

  $scope.testResults = [];
  for (var key in $scope.tests) {
    $scope.testResults.push({name: key, expected: 'passed'});
    if ($scope.tests[key].hasOwnProperty('error')) {
      try {
        $scope.tests[key].actual();
        $scope.testResults[$scope.testResults.length-1].expected = 'An error should have occurred and did not.'
      }
        catch(err) {
          var actual = renderError(err, DEFAULT_ERROR_MESSAGES, BASE_STUDENT_LANGUAGE);
          if (actual !== $scope.tests[key].error) {
            $scope.testResults[$scope.testResults.length-1].expected =  $scope.tests[key].error;
            $scope.testResults[$scope.testResults.length-1].actual =  actual;    
          }
        }
    } else {
      if ($scope.tests[key].expected !== $scope.tests[key].actual) {
        $scope.testResults[$scope.testResults.length-1].expected =  $scope.tests[key].expected;
        $scope.testResults[$scope.testResults.length-1].actual =  $scope.tests[key].actual;      
      }
    }
  }
}
